using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Configuration;
using System.Security.Principal;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
using Novell.Directory.Ldap;
using ldapAccountGen;

namespace ldapAccountGen
{
    /// <summary>
    /// Summary description for LDAPUser.
    /// </summary>
    public class LDAPUser
    {
        // Get Project Settings
        private Properties.Settings settings = Properties.Settings.Default;

        LdapConnection conn = new LdapConnection();

        public LDAPUser()
        {
            conn = doConnect();
        }
        public LdapConnection doConnect()
        {
            string ldapHost = settings.CURRENT_LDAP_SERVER;
            string ldapDN = "cn=" + settings.USER + ",o=" + settings.ORG;
            int ldapPort = System.Convert.ToInt16(settings.PORT);
            
            conn.Connect(ldapHost, ldapPort);
            if (conn.Connected == true)
            {
                try
                {
                    conn.Bind(ldapDN, settings.PWD);
                }
                catch (LdapException exp)
                {
                    throw exp;
                }
            }
            return conn;
        }
        public string createAccount(User user)
        {
            Colleges colleges = new Colleges();
            string col = colleges.getValue(user.college);
            string expTime = endDate(DateTime.Now, 11);
            string dn = "cn=" + user.cn + ",ou=" + col + ",ou="+ settings.PARENT +",o=" + settings.ORG;
            user.dn = dn;
            
            LdapAttributeSet attrSet = new LdapAttributeSet();
            attrSet.Add(  new LdapAttribute("objectclass", "inetOrgPerson"));
            attrSet.Add(  new LdapAttribute("cn", user.cn));
            attrSet.Add(  new LdapAttribute("sn", user.sn));
            attrSet.Add(  new LdapAttribute("givenname", user.gn));            
            attrSet.Add(  new LdapAttribute("userpassword", user.password));
            attrSet.Add(  new LdapAttribute("passwordExpirationTime", expTime));            
            attrSet.Add(  new LdapAttribute("l", user.major));
            attrSet.Add(  new LdapAttribute("departmentNumber", user.college));
            attrSet.Add(  new LdapAttribute("passwordRequired", "TRUE"));
            attrSet.Add(  new LdapAttribute("ou", col));
            attrSet.Add(  new LdapAttribute("title", user.area));
            //attrSet.Add(  new LdapAttribute("fullname", user.gn + " "+ user.sn));
            //attrSet.Add(  new LdapAttribute("loginExpirationTime", expTime));
            //attrSet.Add(  new LdapAttribute("ndsHomeDirectory", user.homeDir));

            sbyte[] studentLoginAllowedTimeMap = {
                    -1,
                     3, -64, -1, -1, -1, -1,
                     3, -64, -1, -1, -1, -1,
                     3, -64, -1, -1, -1, -1,
                     3, -64, -1, -1, -1, -1,
                     3, -64, -1, -1, -1, -1,
                     3, -64, -1, -1, -1, -1,
                     3, -64, -1, -1, -1};
            //attrSet.Add( new LdapAttribute("loginAllowedTimeMap", studentLoginAllowedTimeMap));

            LdapEntry newEntry = new LdapEntry( user.dn, attrSet );
            string log = "";
            try
            {
                conn.Add( newEntry );
            }
            catch(LdapException exp)
            {
                log = "Error: " + exp.Message +"::"+ exp.ResultCode +"::"+ exp.Source + " [On user: " + user.cn + "]";
            }
            return log;
        }
        public string setDefaults(User user, string[] userAcc, int howLong)
        {
            string expTime = endDate(DateTime.Now, howLong);
            try
            {
                Colleges colleges = new Colleges();
                string col = colleges.getValue(user.college);
                ArrayList modList = new ArrayList();
                LdapAttributeSet attrSet = new LdapAttributeSet();

                //LdapAttribute attribute = new LdapAttribute("loginexpirationtime", expTime);
                //modList.Add( new LdapModification(LdapModification.REPLACE, attribute));

                LdapAttribute attribute = new LdapAttribute("passwordExpirationTime", expTime);
                modList.Add(new LdapModification(LdapModification.REPLACE, attribute));

                // Let's check for the values and if not set then it is an ADD not REPLACE
                // [0]cn [1]sn [2]l [3]gn [4]ou(college) [5](homeDir)
                // [6]department [7]passwordExpirationTime [8]fullname [9]title

                attribute = new LdapAttribute("sn", user.sn);
                if (userAcc[1] == "")
                {
                    modList.Add(new LdapModification(LdapModification.ADD, attribute));
                }
                else
                {
                    modList.Add(new LdapModification(LdapModification.REPLACE, attribute));
                }
                attribute = new LdapAttribute("givenname", user.gn);
                if (userAcc[3] == "")
                {
                    modList.Add(new LdapModification(LdapModification.ADD, attribute));
                }
                else
                {
                    modList.Add(new LdapModification(LdapModification.REPLACE, attribute));
                }

                attribute = new LdapAttribute("l", user.major);
                if (userAcc[2] == "")
                {
                    modList.Add(new LdapModification(LdapModification.ADD, attribute));
                }
                else
                {
                    modList.Add(new LdapModification(LdapModification.REPLACE, attribute));
                }

                attribute =  new LdapAttribute("ou", col);
                if (userAcc[4] == "")
                {
                    modList.Add(new LdapModification(LdapModification.ADD, attribute));
                }
                else
                {
                    modList.Add( new LdapModification(LdapModification.REPLACE, attribute));
                }

                attribute = new LdapAttribute("departmentNumber", user.college);
                if (userAcc[6] == "")
                {
                    modList.Add(new LdapModification(LdapModification.ADD, attribute));
                }
                else
                {
                    modList.Add(new LdapModification(LdapModification.REPLACE, attribute));
                }

                //attribute = new LdapAttribute("fullname", user.fullName);
                //if (userAcc[8] == "")
                //{
                //    modList.Add(new LdapModification(LdapModification.ADD, attribute));
                //}
                //else
                //{
                //    modList.Add(new LdapModification(LdapModification.REPLACE, attribute));
                //}

                attribute = new LdapAttribute("title", user.area);
                if (userAcc[9] == "")
                {
                    modList.Add(new LdapModification(LdapModification.ADD, attribute));
                }
                else
                {
                    modList.Add(new LdapModification(LdapModification.REPLACE, attribute));
                }

                attribute =  new LdapAttribute("passwordRequired", "TRUE");
                modList.Add( new LdapModification(LdapModification.REPLACE, attribute));

                attribute =  new LdapAttribute("passwordMinimumLength", "5");
                modList.Add( new LdapModification(LdapModification.REPLACE, attribute));

                attribute =  new LdapAttribute("messageServer", "cn=CLUSTERSERVER,o="+ settings.ORG);
                modList.Add( new LdapModification(LdapModification.REPLACE, attribute));

                LdapModification[] mods = new LdapModification[modList.Count];
                Type mtype=Type.GetType("Novell.Directory.LdapModification");
                mods = (LdapModification[])modList.ToArray(typeof(LdapModification));
                conn.Modify(user.dn, mods);
                return "";
            }
            catch(LdapException exp)
            {
                Console.WriteLine("Exption happened during setDefaults for: " + user.dn);
                //throw exp;
                return exp.Message.ToString();
            }
        }
        public void moveUser(User user)
        {
            if (user.dn != user.newDn)
            {
                try
                {
                    conn.Rename(user.dn, user.newDn, true);
                }
                catch(LdapException exp)
                {
                    //throw exp;
                }
            }
        }
        public string removeAccount(string dn)
        {
            try
            {
                conn.Delete(dn);
            }
            catch (LdapException exp)
            {
                return exp.Message;
            }
            return "";
        }
        public Hashtable UserTable(string sText, string sBy, string sContext)
        {
            Hashtable ut = new Hashtable();
            string searchFilter = "("+ sBy +"=" + sText + ")(objectclass=*)";
            string searchBase = sContext + ",o=" + settings.ORG;
            LdapSearchResults lsc=conn.Search(
                        searchBase
                    ,   LdapConnection.SCOPE_SUB
                    ,   searchFilter
                    ,   null
                    ,   false   );
            
            while (lsc.hasMore())
            {
                LdapEntry nextEntry = null;
                try
                {
                    nextEntry = lsc.next();
                }
                catch(LdapException exp)
                {
                    string sErrors = "Error: " + exp.LdapErrorMessage;
                    sErrors += exp.ResultCode;
                    //return sErrors;
                    continue;
                }
                try
                {
                    LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
                    System.Collections.IEnumerator ienum=attributeSet.GetEnumerator();
                    string dn = "";
                    string[] uRow = new string[10];
                    while(ienum.MoveNext())
                    {
                        DataColumn uc = new DataColumn();
                        LdapAttribute attribute = (LdapAttribute)ienum.Current;
                        string attributeName = attribute.Name;
                        string attributeVal = attribute.StringValue;
                        switch (attributeName)
                        {
                            case "cn":
                                uRow[0] = attributeVal;
                                break;
                            case "sn":
                                uRow[1] = attributeVal;
                                break;
                            case "l":
                                uRow[2] = attributeVal;
                                break;
                            case "givenName":
                                uRow[3] = attributeVal;
                                break;
                            case "ou":
                                uRow[4] = attributeVal;
                                break;
                            case "ndsHomeDirectory":
                                uRow[5] = attributeVal;
                                break;
                            case "departmentNumber":
                                uRow[6] = attributeVal;
                                break;
                            case "passwordExpirationTime":
                                uRow[7] = attributeVal;
                                break;
                            case "fullname":
                                uRow[8] = attributeVal;
                                break;
                            case "title":
                                uRow[9] = attributeVal;
                                break;
                            case "ACL":
                                dn = parseUserOU(attributeName,attributeVal)+",o="+settings.ORG;
                                break;
                            default:
                                break;
                        }                        
                    }
                    dn = "cn=" + uRow[0] + "," + dn;
                    // Add entry to UserTable
                    ut.Add(dn, uRow);                    
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return ut;
        }
        public string createOU(string parentDN)
        {
            string log = "";
            LdapAttributeSet attrSet = new LdapAttributeSet();
            attrSet.Add(new LdapAttribute("objectclass", "organizationalUnit"));

            LdapEntry newEntry = new LdapEntry(parentDN, attrSet);
            try
            {
                conn.Add(newEntry);
                log += "Added: " + parentDN;
            }
            catch (LdapException exp)
            {
                throw exp;
                //string errorCode = exp.ResultCode.ToString();
                //if (errorCode == "68")
                //{
                //      log += "OU: " + ou + " already exists<BR>";
                //}
                //else
                //{
                //      log += "Error: " + exp.LdapErrorMessage + "<BR>";
                //}
            }
            return log;
        }
        private string endDate(DateTime value, int weeks)
        {
            int totalDays = weeks * 7;
            TimeSpan span = new TimeSpan(totalDays, 0, 0, 0, 0);
            DateTime dateFinal = value + span;
            string expTime = UTC2LDAP(dateFinal);
            return expTime;
        }
        private string UTC2LDAP(DateTime value)
        {
            if (value.ToString() != "")
            {
                return value.ToString("yyyyMMddHHmm'Z'");
            }
            else
            {
                return null;
            }
        }
        private string parseUserOU(string attributeName, string attributeVal)
        {
            string[] ous = attributeVal.Split(',');
            Stack souPath = new Stack();
            for (int i = 0; i <= ous.Length - 1; i++)
            {
                string[] ouPts = ous[i].Split('=');
                for (int y = 0; y <= ouPts.Length - 1; y++)
                {
                    if (ouPts[y] == "ou")
                    {
                        souPath.Push("ou=" + ouPts[y + 1]);
                    }
                }
            }
            string[] ouPath = new string[souPath.Count];
            souPath.CopyTo(ouPath, 0);
            Array.Reverse(ouPath, 0, ouPath.Length);
            string userOU = string.Join(",", ouPath);
            return userOU;
        }
    }
}

